package com.cai310.lottery.service.lottery.jczq.impl;

import java.math.BigDecimal;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.cai310.lottery.JczqConstant;
import com.cai310.lottery.common.Lottery;
import com.cai310.lottery.common.SalesMode;
import com.cai310.lottery.common.SchemePrintState;
import com.cai310.lottery.common.SchemeState;
import com.cai310.lottery.common.SubscriptionWay;
import com.cai310.lottery.common.TransactionType;
import com.cai310.lottery.common.WinRecordType;
import com.cai310.lottery.common.WinningUpdateStatus;
import com.cai310.lottery.dto.lottery.jczq.JczqSchemeDTO;
import com.cai310.lottery.entity.lottery.Period;
import com.cai310.lottery.entity.lottery.PrintInterface;
import com.cai310.lottery.entity.lottery.jczq.JczqMatch;
import com.cai310.lottery.entity.lottery.jczq.JczqScheme;
import com.cai310.lottery.entity.lottery.jczq.JczqSchemeMatch;
import com.cai310.lottery.entity.lottery.jczq.JczqSingleScheme;
import com.cai310.lottery.entity.lottery.ticket.Ticket;
import com.cai310.lottery.entity.user.Transaction;
import com.cai310.lottery.entity.user.User;
import com.cai310.lottery.exception.DataException;
import com.cai310.lottery.service.ServiceException;
import com.cai310.lottery.service.lottery.PeriodEntityManager;
import com.cai310.lottery.service.lottery.PrintEntityManager;
import com.cai310.lottery.service.lottery.SchemeEntityManager;
import com.cai310.lottery.service.lottery.dczc.MatchNotEndException;
import com.cai310.lottery.service.lottery.impl.SchemeServiceImpl;
import com.cai310.lottery.service.lottery.jczq.JczqMatchEntityManager;
import com.cai310.lottery.service.lottery.jczq.JczqSchemeService;
import com.cai310.lottery.service.lottery.jczq.JczqSingleSchemeEntityManager;
import com.cai310.lottery.service.lottery.ticket.impl.TicketEntityManager;
import com.cai310.lottery.support.Item;
import com.cai310.lottery.support.JcWonMatchItem;
import com.cai310.lottery.support.PrintWonItem;
import com.cai310.lottery.support.PrizeWork;
import com.cai310.lottery.support.jczq.JczqCompoundContent;
import com.cai310.lottery.support.jczq.JczqMatchItem;
import com.cai310.lottery.support.jczq.JczqMultiplePassPrizeWork;
import com.cai310.lottery.support.jczq.JczqSimplePrizeWork;
import com.cai310.lottery.support.jczq.PassType;
import com.cai310.lottery.support.jczq.PlayType;
import com.cai310.lottery.support.jczq.TicketItem;
import com.cai310.lottery.ticket.protocol.local.utils.JCZQCPUtil;
import com.cai310.lottery.ticket.protocol.local.utils.QueryPVisitor;
import com.cai310.lottery.utils.BigDecimalUtil;
import com.cai310.utils.JsonUtil;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

@Service("jczqSchemeServiceImpl")
@Transactional
public class JczqSchemeServiceImpl extends SchemeServiceImpl<JczqScheme, JczqSchemeDTO> implements JczqSchemeService {

	@Autowired
	private JczqSchemeEntityManagerImpl schemeManager;
  
	@Autowired
	private JczqMatchEntityManager matchEntityManager;
	
	@Autowired
	private JczqSingleSchemeEntityManager jczqSingleSchemeEntityManager;


	@Resource
	protected PeriodEntityManager periodManager;
	@Resource
	protected TicketEntityManager ticketEntityManager;
	
	@Resource
	protected PrintEntityManager printEntityManager;

	@Override
	protected SchemeEntityManager<JczqScheme> getSchemeEntityManager() {
		return schemeManager;
	}

	public void updatePrize(long schemeId) {
		updateResult(schemeId);
	}

	public void updateResult(long schemeId) {
		JczqScheme scheme = schemeManager.getScheme(schemeId);
		if (scheme == null)
			throw new ServiceException("方案不存在.");
		if (scheme.isUpdateWon())
			throw new ServiceException("方案[" + scheme.getSchemeNumber() + "]已更新中奖,不能再更新中奖.");
		else if (scheme.isUpdatePrize())
			throw new ServiceException("方案[" + scheme.getSchemeNumber() + "]已更新奖金,不能再更新中奖.");
		else if (scheme.isPrizeSended())
			throw new ServiceException("方案[" + scheme.getSchemeNumber() + "]已派奖,不能再更新中奖.");

		JczqCompoundContent compoundConent = scheme.getCompoundContent();
		List<JczqMatchItem> itemList = compoundConent.getItems();

		List<String> matchKeys = Lists.newArrayList();
		for (JczqMatchItem item : itemList) {
			matchKeys.add(item.getMatchKey());
		}

		List<JczqMatch> mathList = matchEntityManager.findMatchs(matchKeys);
		Map<String, JczqMatch> drawdMatchMap = Maps.newHashMap();
		for (JczqMatch match : mathList) {
			String matchKey = match.getMatchKey();
			if (!match.isEnded() && !match.isCancel())
				throw new ServiceException("[" + matchKey + "]未结束.");
			Item rs = null;
			if(PlayType.MIX.equals(scheme.getPlayType())){
				for (JczqMatchItem matchItem : itemList) {
					if(matchItem.getMatchKey().equals(match.getMatchKey())){
						 rs = match.getResult(matchItem.getPlayType());	
					}
				}
			}else{
				 rs = match.getResult(scheme.getPlayType());
			}
			if (!match.isCancel() && rs == null)
				throw new ServiceException("[" + matchKey + "]未填开奖结果.");
			drawdMatchMap.put(matchKey, match);
		}

		PrizeWork prizeWork;
		List<JcWonMatchItem> correctList = Lists.newArrayList();
		List<PassType> passTypeList = scheme.getPassTypeList();
		switch (scheme.getPassMode()) {
		case SINGLE:
			for (JczqMatchItem matchItem : itemList) {
				String matchKey = matchItem.getMatchKey();

				JcWonMatchItem wonItem = new JcWonMatchItem();
				wonItem.setMatchKey(matchKey);
				wonItem.setSelectCount(matchItem.selectedCount());

				JczqMatch match = drawdMatchMap.get(matchKey);
				boolean won = false;
				if (match.isCancel()) {
					wonItem.setCancel(true);
					won = true;
				} else if (match.isEnded()) {
					Item rs = match.getResult(scheme.getPlayType());
					if (matchItem.hasSelect(rs)) {
						wonItem.setResultItem(rs);
						if(PlayType.BF.equals(scheme.getPlayType())){
								List<Map<String, Map<String, Double>>> printAwardList = null;
								try {
									printAwardList = scheme.getPrintAwardList();
									if (printAwardList.size() != 1)
										throw new ServiceException("出票SP值数据异常-SPsize不等于1.");
									Map<String, Map<String, Double>> matchPrintAwardMap = null;
									if (printAwardList != null && printAwardList.size() == 1) {
										matchPrintAwardMap = printAwardList.get(0);
										Map<String, Double> printAwardMap = matchPrintAwardMap.get(matchKey);
										Object printAwardObj  = printAwardMap.get(rs.getValue());
										if (printAwardObj == null )
											throw new MatchNotEndException("出票SP值未更新.");
										Double printAward = Double.valueOf(""+printAwardObj);
										if (printAward == null || printAward <= 0)
											throw new MatchNotEndException("出票SP值未更新.");
	
										wonItem.setAward(printAward*2);
									}
								} catch (Exception e) {
									Double resultAward = match.getResultSp(scheme.getPlayType());
									if (resultAward == null || resultAward == 0)
										throw new MatchNotEndException("[#" + match.getId() + "]["
												+ scheme.getPlayType().getText() + "]最终SP值未更新.");
									wonItem.setAward(resultAward);
								}
							
						}else{
					        Double resultAward = match.getResultSp(scheme.getPlayType());
							if (resultAward == null || resultAward == 0)
								throw new MatchNotEndException("[#" + match.getId() + "]["
										+ scheme.getPlayType().getText() + "]最终SP值未更新.");
							wonItem.setAward(resultAward);
						}
						won = true;
					}
				}
				if (won)
					correctList.add(wonItem);
			}

			if (passTypeList.size() > 1)
				throw new ServiceException("过关类型异常.");

			prizeWork = new JczqSimplePrizeWork(scheme.getPassMode(), scheme.getMultiple(), passTypeList.get(0),
					correctList);
			break;
		case PASS:
		case MIX_PASS:
			if (scheme.getState() == SchemeState.CANCEL || scheme.getState() == SchemeState.REFUNDMENT) {
				prizeWork = null;
			} else {
				if (!scheme.isRealPrinted())
					throw new MatchNotEndException("出票SP值未更新.");

				List<TicketItem> ticketList;
				List<Map<String, Map<String, Double>>> printAwardList;
				try {
					ticketList = scheme.getTicketList();
					printAwardList = scheme.getPrintAwardList();
				} catch (DataException e) {
					throw new ServiceException(e.getMessage(), e);
				}
				if (printAwardList.size() != ticketList.size())
					throw new ServiceException("出票SP值数据异常.");

				if (ticketList.size() > 1) {
					for (Map<String, Map<String, Double>> map : printAwardList) {
						if (map == null)
							throw new MatchNotEndException("出票SP值未更新.");
					}

					prizeWork = new JczqMultiplePassPrizeWork(scheme.getPlayType(), scheme.getPassMode(), itemList,
							ticketList, printAwardList, drawdMatchMap);
				} else {
					Map<String, Map<String, Double>> matchPrintAwardMap = null;
					if (printAwardList != null && printAwardList.size() == 1) {
						matchPrintAwardMap = printAwardList.get(0);
						for (int i = 0; i < itemList.size(); i++) {
							JczqMatchItem matchItem = itemList.get(i);
							String matchKey = matchItem.getMatchKey();

							JcWonMatchItem wonItem = new JcWonMatchItem();
							wonItem.setMatchKey(matchKey);
							wonItem.setSelectCount(matchItem.selectedCount());

							JczqMatch match = drawdMatchMap.get(matchKey);
							boolean won = false;
							if (match.isCancel()) {
								wonItem.setAward(1d);
								wonItem.setCancel(true);
								wonItem.setAward(1d);
								won = true;
							} else if (match.isEnded()) {
								Map<String, Double> printAwardMap = matchPrintAwardMap.get(matchKey);
								Item rs = null;
								if(PlayType.MIX.equals(scheme.getPlayType())){
									 rs = match.getResult(matchItem.getPlayType());	
								}else{
									 rs = match.getResult(scheme.getPlayType());
								}
								Object printAwardObj = null;
								if (matchItem.hasSelect(rs)) {
									printAwardObj = printAwardMap.get(rs.getValue());
									if (printAwardObj == null )
										throw new MatchNotEndException("出票SP值未更新.");
									Double printAward = Double.valueOf(""+printAwardObj);
									if (printAward == null || printAward <= 0)
										throw new MatchNotEndException("出票SP值未更新.");

									wonItem.setAward(printAward);
									wonItem.setResultItem(rs);
									won = true;
								}
							}
							if (won)
								correctList.add(wonItem);
						}

						if (passTypeList.size() > 1)
							throw new ServiceException("过关类型异常.");

						prizeWork = new JczqSimplePrizeWork(scheme.getPassMode(), scheme.getMultiple(),
								passTypeList.get(0), correctList);
					} else {
						////没有出票，退款。把场次设为取消
						for (int i = 0; i < itemList.size(); i++) {
							JczqMatchItem matchItem = itemList.get(i);
							String matchKey = matchItem.getMatchKey();

							JcWonMatchItem wonItem = new JcWonMatchItem();
							wonItem.setMatchKey(matchKey);
							wonItem.setSelectCount(matchItem.selectedCount());
							boolean won = true;
							wonItem.setCancel(true);
							if (won)
								correctList.add(wonItem);
						}

						if (passTypeList.size() > 1)
							throw new ServiceException("过关类型异常.");

						prizeWork = new JczqSimplePrizeWork(scheme.getPassMode(), scheme.getMultiple(),
								passTypeList.get(0), correctList);
					}

					
				}
			}
			break;
		default:
			throw new ServiceException("过关模式不合法.");
		}

		if (prizeWork != null && prizeWork.isWon()) {
			try {
				scheme.doUpdateResult(prizeWork.getWonDetail().toString());
				scheme.doUpdatePrize(BigDecimal.valueOf(prizeWork.getTotalPrize()),
						BigDecimal.valueOf(prizeWork.getTotalPrizeAfterTax()), prizeWork.getPrizeDetail().toString());
			
			} catch (DataException e) {
				throw new ServiceException(e.getMessage());
			}
		} else {
			scheme.setWinningUpdateStatus(WinningUpdateStatus.PRICE_UPDATED);
			scheme.setWon(false);
			scheme.setWonDetail("");
			scheme.setPrize(BigDecimal.ZERO);
			scheme.setPrizeAfterTax(BigDecimal.ZERO);
			scheme.setPrizeDetail("");
		}
		scheme = getSchemeEntityManager().saveScheme(scheme);
	}

	@Override
	protected JczqScheme newSchemeInstance(JczqSchemeDTO schemeDTO) {
		JczqScheme scheme = super.newSchemeInstance(schemeDTO);

		scheme.setPlayType(schemeDTO.getPlayType());
		scheme.setSchemeType(schemeDTO.getSchemeType());
		scheme.setPassMode(schemeDTO.getPassMode());
		scheme.setTicketContent(schemeDTO.getTicketContent());

		long passTypeValue = 0;
		for (PassType passType : schemeDTO.getPassTypes()) {
			passTypeValue |= passType.getValue();
		}
		scheme.setPassType(passTypeValue);

		return scheme;
	}

	@Override
	public JczqScheme createScheme(JczqSchemeDTO schemeDTO) {
		JczqScheme scheme = super.createScheme(schemeDTO);

		if (scheme.getMode() == SalesMode.COMPOUND) {
			JczqCompoundContent compoundContent = scheme.getCompoundContent();
			if (compoundContent != null) {
				for (JczqMatchItem matchItem : compoundContent.getItems()) {
					JczqSchemeMatch schemeMatch = new JczqSchemeMatch();
					schemeMatch.setMatchKey(matchItem.getMatchKey());
					schemeMatch.setSchemeId(scheme.getId());
					schemeManager.saveSchemeMatch(schemeMatch);
				}
			}
		}

		return scheme;
	}
	@Override
	public JczqScheme createSingleScheme(JczqSchemeDTO schemeDTO,JczqSingleScheme jczqSingleScheme,Integer index) throws DataException {
		JczqScheme scheme = super.createScheme(schemeDTO);

		if (scheme.getMode() == SalesMode.COMPOUND) {
			JczqCompoundContent compoundContent = scheme.getCompoundContent();
			if (compoundContent != null) {
				for (JczqMatchItem matchItem : compoundContent.getItems()) {
					JczqSchemeMatch schemeMatch = new JczqSchemeMatch();
					schemeMatch.setMatchKey(matchItem.getMatchKey());
					schemeMatch.setSchemeId(scheme.getId());
					schemeManager.saveSchemeMatch(schemeMatch);
				}
			}
		}
		jczqSingleScheme.updateSchemes(index, scheme.getSchemeNumber());
		jczqSingleSchemeEntityManager.saveJczqSingleScheme(jczqSingleScheme);
		return scheme;
	}
	public JczqScheme destineScheme(JczqSchemeDTO schemeDTO) {
		Period period = periodManager.getPeriod(schemeDTO.getPeriodId());
		checkConformPeriodInitConfig(period, schemeDTO);
		JczqScheme scheme = newSchemeInstance(schemeDTO);
		scheme.setPeriodNumber(period.getPeriodNumber());
		scheme.setSchemePrintState(SchemePrintState.UNPRINT);
		return scheme;
	}
	
	@Override
	protected void checkConformPeriodSubscriptionConfig(JczqScheme scheme) {
		super.checkConformPeriodSubscriptionConfig(scheme);

		List<JczqMatch> matchList = matchEntityManager.findMatchsOfUnEnd();
		List<String> keyList = Lists.newArrayList();
		if (matchList != null && !matchList.isEmpty()) {
			for (JczqMatch m : matchList) {
				keyList.add(m.getMatchKey());
			}
		}

		switch (scheme.getMode()) {
		case COMPOUND:
			JczqCompoundContent content = scheme.getCompoundContent();
			for (JczqMatchItem item : content.getItems()) {
				if (!keyList.contains(item.getMatchKey()))
					throw new ServiceException("第" + (item.getMatchKey()) + "场赛事已经截止销售.");
			}
			break;
		case SINGLE:
			throw new ServiceException("目前暂不支持单式.");
		default:
			throw new ServiceException("投注方式不正确.");
		}
	}

	@Override
	public boolean isSaleEnded(Long schemeId) {
		boolean isSaleEnded = super.isSaleEnded(schemeId);

		if (!isSaleEnded) {
			List<JczqMatch> matchList = matchEntityManager.findMatchsOfUnEnd();
			List<String> keyList = Lists.newArrayList();
			if (matchList != null && !matchList.isEmpty()) {
				for (JczqMatch m : matchList) {
					keyList.add(m.getMatchKey());
				}
			}
			JczqScheme scheme = getSchemeEntityManager().getScheme(schemeId);
			switch (scheme.getMode()) {
			case COMPOUND:
				JczqCompoundContent content = scheme.getCompoundContent();
				for (JczqMatchItem item : content.getItems()) {
					if (!keyList.contains(item.getMatchKey())) {
						isSaleEnded = true;
						break;
					}
				}
				break;
			case SINGLE:
				throw new ServiceException("目前暂不支持单式.");
			default:
				throw new ServiceException("投注方式不正确.");
			}
		}
		return isSaleEnded;
	}

	@SuppressWarnings("unchecked")
	@Override
	protected void checkConformPeriodInitConfig(Period period, JczqSchemeDTO schemeDTO) {
		super.checkConformPeriodInitConfig(period, schemeDTO);

		List<JczqMatch> matchList = matchEntityManager.findMatchsOfUnEnd();
		Map<String,JczqMatch> keyMap = Maps.newHashMap();
		if (matchList != null && !matchList.isEmpty()) {
			for (JczqMatch m : matchList) {
				keyMap.put(m.getMatchKey(),m);
			}
		}
		Date endTime = null;
		switch (schemeDTO.getMode()) {
		case COMPOUND:
			@SuppressWarnings("rawtypes")
			Map classMap = new HashMap();
			classMap.put("items", JczqMatchItem.class);
			JczqCompoundContent content = JsonUtil.getObject4JsonString(schemeDTO.getContent(),
					JczqCompoundContent.class, classMap);
			JczqMatch jczqMatch = null;
			for (JczqMatchItem item : content.getItems()) {
				if (!keyMap.containsKey(item.getMatchKey()))
					throw new ServiceException("第" + (item.getMatchKey()) + "场赛事已经截止销售.");
				jczqMatch = keyMap.get(item.getMatchKey());
				try {
					if (endTime == null || endTime.after(jczqMatch.getTicketOfficialEndTime()))
						endTime = jczqMatch.getTicketOfficialEndTime();
				} catch (DataException e) {
					throw new ServiceException("获取比赛场次时间错误.");
				}
			}
			schemeDTO.setOfficialEndTime(endTime);
			break;
		case SINGLE:
			throw new ServiceException("目前暂不支持单式.");
		default:
			throw new ServiceException("投注方式不正确.");
		}
	}
	public boolean handleTransaction(JczqScheme scheme,List<String> endLineIds) {
		boolean anyEnded = false;// 方案是否包含一场已结束的赛事标识
		List<String> matchKeys = scheme.getSelectedMatchKeys();
		for (String endLineId : endLineIds) {
			if (matchKeys.contains(endLineId)) {
				anyEnded = true;
				break;
			}
		}
		if (anyEnded) {
			commitOrCancelTransaction(scheme.getId());
			return true;
		}

		return false;
	}
	@Override
	public Lottery getLotteryType() {
		return Lottery.JCZQ;
	}
}
